﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Windows.Forms;

namespace 电磁检测系统
{
    public partial class Form1 : Form
    {
        AutoResizeForm asc = new AutoResizeForm();

        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//设置该属性 为false
        }


        double magnification = 1;

        /*******串口检测程序，用来检测系统接入的串口*******/

        private void btn_Detect_Click(object sender, EventArgs e)
        {
            string[] ArrayPort = SerialPort.GetPortNames(); //获取当前计算机连接的串口名
            cbx_SerialPort.Items.Clear(); //清除当前组合框下拉菜单内容
            //将串口名数组中的串口逐个添加到串口选择下拉菜单
            for (int i = 0; i < ArrayPort.Length; i++)
            {
                cbx_SerialPort.Items.Add(ArrayPort[i]);
            }
        }


        /********窗口加载程序**********/

        private void Form1_Load(object sender, EventArgs e)
        {
            asc.controllInitializeSize(this);
            btn_Open.Text = "打开串口"; //窗口加载时，保证“打开串口”按钮的文本内容是正确的
            //窗口加载时，没打开串口，无法开始或停止检测
            btn_Start.Enabled = false;
            btn_Stop.Enabled = false;
            cbx_Sample.Enabled = false;

            asc.controlAutoSize(this);

        }

        /********串口开关**********/

        private void btn_Open_Click(object sender, EventArgs e)
        {
            if (btn_Open.Text == "打开串口") //串口关闭时
            {
                try
                {
                    serialPort1.PortName = cbx_SerialPort.Text; //将下拉菜单选中的串口传递给串口控件
                    serialPort1.Open(); //打开串口
                    btn_Detect.Enabled = false; //串口检测设为不可用
                    btn_Open.Text = "关闭串口"; //串口开关键变为“关闭串口”
                    //控制模块区域控件可用
                    btn_Start.Enabled = true;
                    btn_Stop.Enabled = true;
                    cbx_Sample.Enabled = true;
                    cbx_SerialPort.Enabled = false;
                }
                catch
                {
                    MessageBox.Show("打开串口失败，请检查串口", "错误");
                }
            }
            else //串口打开时
            {
                try
                {
                    serialPort1.Close(); //关闭串口
                    btn_Detect.Enabled = true; //串口检测恢复可用
                    btn_Open.Text = "打开串口"; //串口开关键变为“打开串口”
                    //控制区域模块不可用
                    btn_Start.Enabled = false;
                    btn_Stop.Enabled = false;
                    cbx_Sample.Enabled = false;
                    cbx_SerialPort.Enabled = true;
                }
                catch
                {
                    MessageBox.Show("关闭串口失败，请检查串口", "错误");
                }
            }
        }

        /******定义一个List，用于保存串口接收到的合并后的16位数据******/
        List<byte> dataList = new List<byte>();

        /********串口接收数据********/

        private void DataReceive(object sender, SerialDataReceivedEventArgs e)
        {
            int length = serialPort1.BytesToRead; //读取串口接收缓冲区字节数
            Byte[] data = new Byte[length]; //定义相同字节的数组
            serialPort1.Read(data, 0, length); //串口读取缓冲区数据到数组中
            try
            {
                for (int i = 0; i < length; i++)
                {
                    lock (dataList) //加锁，防止报错，不知道为什么
                    {
                        dataList.Add(data[i]);

                    }
                }
            }
            catch { }
        }



        /*********各个通道数据队列************/
        Queue<double> ch1 = new Queue<double>(sample);
        Queue<double> ch2 = new Queue<double>(sample);
        Queue<double> ch3 = new Queue<double>(sample);
        Queue<double> ch4 = new Queue<double>(sample);
        Queue<double> ch5 = new Queue<double>(sample);
        Queue<double> ch6 = new Queue<double>(sample);
        Queue<double> ch7 = new Queue<double>(sample);
        Queue<double> ch8 = new Queue<double>(sample);
        Queue<double> ch9 = new Queue<double>(sample);
        Queue<double> ch10 = new Queue<double>(sample);
        Queue<double> ch11 = new Queue<double>(sample);
        Queue<double> ch12 = new Queue<double>(sample);


        static UInt16 sample = 200;


        /**********更新ch1-ch8队列********/
        private void queueUpdate(double data1, double data2, double data3, double data4, double data5, double data6, double data7, double data8, double data9, double data10, double data11, double data12)
        {
            if (ch1.Count > sample)
            {
                ch1.Dequeue();
            }
            ch1.Enqueue(data1);

            if (ch2.Count > sample)
            {
                ch2.Dequeue();
            }
            ch2.Enqueue(data2);

            if (ch3.Count > sample)
            {
                ch3.Dequeue();
            }
            ch3.Enqueue(data3);

            if (ch4.Count > sample)
            {
                ch4.Dequeue();
            }
            ch4.Enqueue(data4);

            if (ch5.Count > sample)
            {
                ch5.Dequeue();
            }
            ch5.Enqueue(data5);

            if (ch6.Count > sample)
            {
                ch6.Dequeue();
            }
            ch6.Enqueue(data6);

            if (ch7.Count > sample)
            {
                ch7.Dequeue();
            }
            ch7.Enqueue(data7);

            if (ch8.Count > sample)
            {
                ch8.Dequeue();
            }
            ch8.Enqueue(data8);

            if (ch9.Count > sample)
            {
                ch9.Dequeue();
            }
            ch9.Enqueue(data9);

            if (ch10.Count > sample)
            {
                ch10.Dequeue();
            }
            ch10.Enqueue(data10);

            if (ch11.Count > sample)
            {
                ch11.Dequeue();
            }
            ch11.Enqueue(data11);

            if (ch12.Count > sample)
            {
                ch12.Dequeue();
            }
            ch12.Enqueue(data12);

        }












        /****数据文件保存到本地的路径****/
        string fdbPath;



        /*********保存路径选择*******/

        private void btn_Path_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            //显示保存路径对话框
            fbd.ShowDialog();
            //将选择的路径保存到文本框中
            fdbPath = fbd.SelectedPath;
            textBox1.Text = fdbPath;
        }


        /*************清除路径************/

        private void btn_ClearPath_Click(object sender, EventArgs e)
        {
            //清除文本框
            textBox1.Clear();
        }




        /********向下位机发送开始采样命令********/
        private void btn_Start_Click(object sender, EventArgs e)
        {
            //采样率设置不可用
            cbx_Sample.Enabled = false;
            //配置下位机采样模式
            if (cbx_Sample.Text == "") //如果没有选择采样模式，就默认选择时间采样
            {
                cbx_Sample.SelectedIndex = 0;
                serialPort1.WriteLine("TIMER");
            }
            else
            {
                switch (cbx_Sample.SelectedIndex)
                {
                    case 0:
                        serialPort1.WriteLine("TIMER");
                        break;
                    case 1:
                        serialPort1.WriteLine("ENCODER");
                        break;
                }
            }
            /*做一个延时*/
            for (int i = 0; i < 100; i++)
            {

            }

            timer1.Enabled = true;
            timer2.Enabled = true;
            btn_Start.Enabled = false; // 开始按钮不可选
            btn_Stop.Enabled = true; // 停止按钮可选
            btn_Open.Enabled = false; //串口打开按钮不可选


        }


        /********向下位机发送停止采样命令******/

        private void btn_Stop_Click(object sender, EventArgs e)
        {
            try
            {
                serialPort1.WriteLine("STOP"); //向下位机发送停止检测命令

            }

            catch (Exception)
            {
                MessageBox.Show("串口断开连接，请检查串口。", "错误");
            }

            cbx_Sample.Enabled = true;
            timer2.Enabled = false;

            while (serialPort1.BytesToRead != 0) ;


            byte[] dataProcessU16 = dataList.ToArray();

            

            List<ushort> dataToWriteList = new List<ushort>();
            for (int i = 0; i < dataProcessU16.Length; i = i + 2)
            {
                if (i + 2 > dataProcessU16.Length) break; //防止数组超出索引报错
                dataToWriteList.Add(DataProcess.ByteToU16(dataProcessU16[i], dataProcessU16[i + 1]));

            }
            UInt16[] dataToWriteArray = dataToWriteList.ToArray();
            //将采集到的数据保存到本地
            //若没有设置保存路径
            if (textBox1.Text == "")
            {
                string currentFilefold = Directory.GetCurrentDirectory(); //获取当前exe所在文件夹路径
                string dataFilefold = Directory.CreateDirectory(currentFilefold + @"\Data").ToString(); //创建一个Data文件夹用于存储数据
                using (StreamWriter sw = new StreamWriter(dataFilefold + @"\" + DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss") + ".txt", true))
                {
                    //sw.WriteLine("CH1" + "\t" + "CH2" + "\t" + "CH3" + "\t" + "CH4" + "\t" + "CH5" + "\t" + "CH6" + "\t" + "CH7" + "\t" + "CH8" + "\t" + "CH9" + "\t" + "CH10" + "\t" + "CH11" + "\t" + "CH12");
                    //将dataToWriteArray数组的所有数据一个一个写入文本框
                    for (int i = 0; i < (dataToWriteArray.Length - dataToWriteArray.Length % 12); i++)
                    {

                        //每12个数据换一次行
                        if (i != 0 && (i % 12) == 0)
                        {
                            sw.Write("\n");
                        }
                        //写完一个数据后，加上一个Tab键
                        //sw.Write(Math.Round((dataToWriteArray[i] * 3.3 / 4096 - 1.5), 3) + "\t");
                        if ((i % 12) != 0 && i != 0)
                        {
                            sw.Write("\t");
                        }
                        sw.Write(Math.Round((dataToWriteArray[i] * 3.3 / 4096 - 1.5), 3));

                    }
                }
            }
            //若指定了保存的文件夹
            else
            {
                string dataFilefold = textBox1.Text.ToString();
                using (StreamWriter sw = new StreamWriter(dataFilefold + @"\" + DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss") + ".txt", true))
                {
                    //sw.WriteLine("CH1" + "\t" + "CH2" + "\t" + "CH3" + "\t" + "CH4" + "\t" + "CH5" + "\t" + "CH6" + "\t" + "CH7" + "\t" + "CH8" + "\t" + "CH9" + "\t" + "CH10" + "\t" + "CH11" + "\t" + "CH12");
                    //将dataToWriteArray数组的所有数据一个一个写入文本框
                    for (int i = 0; i < (dataToWriteArray.Length - dataToWriteArray.Length % 12); i++)
                    {
                        //每8个数据换一次行
                        if (i != 0 && (i % 12) == 0)
                        {
                            sw.Write("\n");
                        }
                        if ((i % 12) != 0 && i != 0)
                        {
                            sw.Write("\t");
                        }
                        //写完一个数据后，加上一个Tab键
                        sw.Write(Math.Round((dataToWriteArray[i] * 3.3 / 4096 - 1.5), 3));

                    }
                }
            }

            //清空dataList数据和图标
            dataList.Clear();

            btn_Stop.Enabled = false; //停止按钮不可用
            btn_Start.Enabled = true; //开始按钮可用
            btn_Open.Enabled = true;
        }



        private void timer2_Tick(object sender, EventArgs e)
        {
            if (magnificationBox.Text != "")
                magnification = Convert.ToDouble(magnificationBox.Text.Trim());

            byte[] byteBuffer = new byte[24];

            try
            {
                dataList.CopyTo(dataList.Count - dataList.Count % 24 - byteBuffer.Length, byteBuffer, 0, byteBuffer.Length);//取最新的24个数据
            }
            catch { }
            ushort[] ushortBuffer = new ushort[12];
            //将高低8位合并成16位数据



            ushortBuffer[0] = DataProcess.ByteToU16(byteBuffer[0], byteBuffer[1]);
            ushortBuffer[1] = DataProcess.ByteToU16(byteBuffer[2], byteBuffer[3]);
            ushortBuffer[2] = DataProcess.ByteToU16(byteBuffer[4], byteBuffer[5]);
            ushortBuffer[3] = DataProcess.ByteToU16(byteBuffer[6], byteBuffer[7]);
            ushortBuffer[4] = DataProcess.ByteToU16(byteBuffer[8], byteBuffer[9]);
            ushortBuffer[5] = DataProcess.ByteToU16(byteBuffer[10], byteBuffer[11]);
            ushortBuffer[6] = DataProcess.ByteToU16(byteBuffer[12], byteBuffer[13]);
            ushortBuffer[7] = DataProcess.ByteToU16(byteBuffer[14], byteBuffer[15]);
            ushortBuffer[8] = DataProcess.ByteToU16(byteBuffer[16], byteBuffer[17]);
            ushortBuffer[9] = DataProcess.ByteToU16(byteBuffer[18], byteBuffer[19]);
            ushortBuffer[10] = DataProcess.ByteToU16(byteBuffer[20], byteBuffer[21]);
            ushortBuffer[11] = DataProcess.ByteToU16(byteBuffer[22], byteBuffer[23]);




            //更新各个通道的队列
            queueUpdate(
                        magnification * (Math.Round(ushortBuffer[0] * 3.3 / 4096 - 1.5, 3)) + 1,
                        magnification * (Math.Round(ushortBuffer[1] * 3.3 / 4096 - 1.5, 3)) + 2,
                        magnification * (Math.Round(ushortBuffer[2] * 3.3 / 4096 - 1.5, 3)) + 3,
                        magnification * (Math.Round(ushortBuffer[3] * 3.3 / 4096 - 1.5, 3)) + 4,
                        magnification * (Math.Round(ushortBuffer[4] * 3.3 / 4096 - 1.5, 3)) + 5,
                        magnification * (Math.Round(ushortBuffer[5] * 3.3 / 4096 - 1.5, 3)) + 6,
                        magnification * (Math.Round(ushortBuffer[6] * 3.3 / 4096 - 1.5, 3)) + 7,
                        magnification * (Math.Round(ushortBuffer[7] * 3.3 / 4096 - 1.5, 3)) + 8,
                        magnification * (Math.Round(ushortBuffer[8] * 3.3 / 4096 - 1.5, 3)) + 1,
                        magnification * (Math.Round(ushortBuffer[9] * 3.3 / 4096 - 1.5, 3)) + 2,
                        magnification * (Math.Round(ushortBuffer[10] * 3.3 / 4096 - 1.5, 3)) + 3,
                        magnification * (Math.Round(ushortBuffer[11] * 3.3 / 4096 - 1.5, 3)) + 4
                        );



            formsPlot1.Plot.Clear();
            formsPlot1.Plot.SetAxisLimits(0, 200, 0, 9);
            double[] ch1_show = ch1.ToArray();
            double[] ch2_show = ch2.ToArray();
            double[] ch3_show = ch3.ToArray();
            double[] ch4_show = ch4.ToArray();
            double[] ch5_show = ch5.ToArray();
            double[] ch6_show = ch6.ToArray();
            double[] ch7_show = ch7.ToArray();
            double[] ch8_show = ch8.ToArray();
            double[] ch9_show = ch9.ToArray();
            double[] ch10_show = ch10.ToArray();
            double[] ch11_show = ch11.ToArray();
            double[] ch12_show = ch12.ToArray();

            formsPlot1.Plot.AddSignal(ch1_show);
            formsPlot1.Plot.AddSignal(ch2_show);
            formsPlot1.Plot.AddSignal(ch3_show);
            formsPlot1.Plot.AddSignal(ch4_show);
            formsPlot1.Plot.AddSignal(ch5_show);
            formsPlot1.Plot.AddSignal(ch6_show);
            formsPlot1.Plot.AddSignal(ch7_show);
            formsPlot1.Plot.AddSignal(ch8_show);
            formsPlot1.Plot.AddSignal(ch9_show);
            formsPlot1.Plot.AddSignal(ch10_show);
            formsPlot1.Plot.AddSignal(ch11_show);
            formsPlot1.Plot.AddSignal(ch12_show);
            formsPlot1.Refresh();
            //耗时巨大的代码


        }


        /**********意外关闭窗口时，向下位机发送停止检测命令************/
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                serialPort1.WriteLine("STOP"); //向下位机发送停止检测命令

            }

        }

        private void Form1_AutoSizeChanged(object sender, EventArgs e)
        {
            asc.controlAutoSize(this);
        }

        private void formsPlot1_Load(object sender, EventArgs e)
        {
            formsPlot1.Plot.SetAxisLimits(0, 100, 0, 9);
            formsPlot1.Plot.YAxis.Label("Voltage (V)");
        }

        int row;

        double[] ch1ToShow;
        double[] ch2ToShow;
        double[] ch3ToShow;
        double[] ch4ToShow;
        double[] ch5ToShow;
        double[] ch6ToShow;
        double[] ch7ToShow;
        double[] ch8ToShow;
        double[] ch9ToShow;
        double[] ch10ToShow;
        double[] ch11ToShow;
        double[] ch12ToShow;



        double[] newCh1;
        double[] newCh2;
        double[] newCh3;
        double[] newCh4;
        double[] newCh5;
        double[] newCh6;
        double[] newCh7;
        double[] newCh8;
        double[] newCh9;
        double[] newCh10;
        double[] newCh11;
        double[] newCh12;
        string fileName;

        /// <summary>
        /// 加载数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            // 获取文件路径
            fileName = "";
            OpenFileDialog fileDialog = new OpenFileDialog();
            fileDialog.Multiselect = false; // 不允许多选
            fileDialog.Title = "请选择数据文件";
            fileDialog.Filter = "数据(*.txt)|*.txt";
            fileDialog.InitialDirectory = textBox1.Text;
            if (fileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                fileName = fileDialog.FileName;
            }
            textBox2.Text = fileName;


            //var watch = System.Diagnostics.Stopwatch.StartNew();

            // 导入数据
            // 新建一个读取数据的流
            List<double> arrList = new List<double>();
            string line; // 临时缓冲变量
            try
            {
                StreamReader rd = new StreamReader(fileName);
                while ((line = rd.ReadLine()) != null)
                {
                    // 将该行读取到的数据以分隔符进行划分，并存储到字符串数组中
                    string[] values = line.Split('\t');
                    // 将字符串数组中的数据挨个写入到List中
                    for (int i = 0; i < values.Length; i++)
                    {
                        arrList.Add(double.Parse(values[i]));
                    }
                }

                rd.Close();
            }
            catch(Exception)
            {
                
            }
            // 新建一个List来存储数据


            // 挨行读取txt，直到读不到数据为止

            double[] dataReadFromTxt = arrList.ToArray();
            row = dataReadFromTxt.Length / 12; // 获取数据行数
            double[,] dataToShow = new double[12, row];

            for(int i = 0; i<dataReadFromTxt.Length; i++)
            {
                int j, k;
                j = i % 12;
                k = i / 12;
                dataToShow[j, k] = dataReadFromTxt[i];
            }


            double[] ch1ToShow = new double[row];
            double[] ch2ToShow = new double[row];
            double[] ch3ToShow = new double[row];
            double[] ch4ToShow = new double[row];
            double[] ch5ToShow = new double[row];
            double[] ch6ToShow = new double[row];
            double[] ch7ToShow = new double[row];
            double[] ch8ToShow = new double[row];
            double[] ch9ToShow = new double[row];
            double[] ch10ToShow = new double[row];
            double[] ch11ToShow = new double[row];
            double[] ch12ToShow = new double[row];


            int sizeOfDouble = sizeof(double);

            Buffer.BlockCopy(dataToShow, row * 0 * sizeOfDouble, ch1ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 1 * sizeOfDouble, ch2ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 2 * sizeOfDouble, ch3ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 3 * sizeOfDouble, ch4ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 4 * sizeOfDouble, ch5ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 5 * sizeOfDouble, ch6ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 6 * sizeOfDouble, ch7ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 7 * sizeOfDouble, ch8ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 8 * sizeOfDouble, ch9ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 9 * sizeOfDouble, ch10ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 10 * sizeOfDouble, ch11ToShow, 0, row * sizeOfDouble);
            Buffer.BlockCopy(dataToShow, row * 11 * sizeOfDouble, ch12ToShow, 0, row * sizeOfDouble);

            // 数组偏移得到各个通道

            newCh1 = ch1ToShow.Select(x => x+1).ToArray();
            newCh2 = ch1ToShow.Select(x => x+2).ToArray();
            newCh3 = ch1ToShow.Select(x => x+3).ToArray();
            newCh4 = ch1ToShow.Select(x => x+4).ToArray();
            newCh5 = ch1ToShow.Select(x => x+5).ToArray();
            newCh6 = ch1ToShow.Select(x => x+6).ToArray();
            newCh7 = ch1ToShow.Select(x => x+7).ToArray();
            newCh8 = ch1ToShow.Select(x => x+8).ToArray();



            // 清除图表
            formsPlot1.Plot.Clear();
            formsPlot1.Plot.SetAxisLimits(0, row, 0, 9);

            formsPlot1.Plot.AddSignal(newCh1);
            formsPlot1.Plot.AddSignal(newCh2);
            formsPlot1.Plot.AddSignal(newCh3);
            formsPlot1.Plot.AddSignal(newCh4);
            formsPlot1.Plot.AddSignal(newCh5);
            formsPlot1.Plot.AddSignal(newCh6);
            formsPlot1.Plot.AddSignal(newCh7);
            formsPlot1.Plot.AddSignal(newCh8);



            //watch.Stop();
            //var elapsedMs = watch.ElapsedMilliseconds;


            Console.WriteLine("");

        }

        private void magnificationBox_TextChanged(object sender, EventArgs e)
        {
            if (magnificationBox.Text != "" && double.TryParse(magnificationBox.Text, out magnification))
                magnification = Convert.ToDouble(magnificationBox.Text.Trim());

        }
    }
}


